package com.youlu.campus.web.certificate;

import com.youlu.campus.base.certificate.enums.CertificateStatusEnum;
import com.youlu.campus.service.base.BaseService;
import com.youlu.campus.web.common.base.RequestContext;
import com.youlu.campus.web.certificate.dto.CertificateResponse;
import com.youlu.campus.web.certificate.dto.CertificateSyncRequest;
import com.youlu.campus.web.certificate.dto.YLCertificateFinalImageSyncRequest;
import com.youlu.campus.web.certificate.dto.YLCertificateSyncRequest;
import com.youlu.campus.web.certificate.entity.CertificatePO;
import com.youlu.campus.web.order.service.OrderService;
import com.youlu.campus.web.sign.entity.SignPlanDailyPO;
import com.youlu.campus.web.sign.entity.SignPlanJoinPO;
import com.youlu.campus.web.sign.entity.SignPlanPO;
import com.youlu.campus.web.common.utils.DateTimeUtils;
import com.youlu.campus.service.utils.HttpClientUtils;
import com.youlu.campus.web.common.utils.JsonUtil;
import com.yuelin.infrastructure.quantum.common.QResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * @author zgz
 * @date 2020/12/3 13:02
 */
@Slf4j
@Service
public class CertificateService extends BaseService {

    @Value("${stamp.syncUrl:null}")
    private String syncUrl;

    @Autowired
    private OrderService orderService;


    public List<CertificateResponse> getCertificateInfo() {
        String userId = RequestContext.getUserId();
        log.info("getCertificateInfo userId {}", userId);
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("deleted").is(false));
        List<CertificatePO> certificatePOList = mongoTemplate.find(query, CertificatePO.class);
        List<CertificateResponse> responses = new ArrayList<>();
        for (CertificatePO certificatePO : certificatePOList) {
            CertificateResponse response = new CertificateResponse();
            BeanUtils.copyProperties(certificatePO, response);
            Query dquery = new Query();
            dquery.addCriteria(Criteria.where("userInfo.userId").is(userId));
            dquery.addCriteria(Criteria.where("deleted").is(false));
            List<SignPlanJoinPO> joinPOList = mongoTemplate.find(dquery, SignPlanJoinPO.class);
            boolean isGet = false;
            for (SignPlanJoinPO joinPO : joinPOList) {
                dquery = new Query();
                dquery.addCriteria(Criteria.where("userInfo.userId").is(userId));
                dquery.addCriteria(Criteria.where("signPlanId").is(joinPO.getSignPlanId()));
                dquery.addCriteria(Criteria.where("deleted").is(false));
                List<Long> days = mongoTemplate.findDistinct(dquery, "day", SignPlanDailyPO.class, Long.class);
                //获取打卡总天数
                SignPlanPO signPlanPO = mongoTemplate.findById(joinPO.getSignPlanId(), SignPlanPO.class);
                if (days.size() >= signPlanPO.getTotalDay()) {
                    isGet = true;
                    break;
                }
            }
            if (!isGet) {
                response.setStatus("not_get");
            } else if (!certificatePO.isReceived()) {
                response.setStatus("wait_receive");
            } else {
                response.setStatus("wait_stamp");
            }
            //是否申领过
            if (orderService.hasPaperCertificateOrder(userId, certificatePO.getCertificateType())) {
                response.setStatus("apply");
            }
            responses.add(response);
        }
        return responses;
    }

    public Integer receiveCertificate(String id) {
        log.info("getCertificateInfo id {}", id);
        CertificatePO certificatePO = mongoTemplate.findById(id, CertificatePO.class);
        if (certificatePO != null) {
            certificatePO.setReceived(true);
            certificatePO.setReceiveTime(new Date());
            mongoTemplate.save(certificatePO);
        }
        return 1;
    }

    public boolean syncCertificate(CertificateSyncRequest request) {
        log.info("syncCertificate request {}", request);
        if (isSync(request.getUserId(), request.getCertificateType().getCode())) {
            return false;
        }
        String lock = "youlu:certificate:data:sync:" + request.getCertificateType().getCode();
        if (lockService.tryLock(lock, 10L, TimeUnit.SECONDS)) {
            try {
                CertificatePO certificatePO = new CertificatePO();
                BeanUtils.copyProperties(request, certificatePO);
                //获取最大证书编号
                Long certificateNo = this.getMaxCertificateNo(request.getCertificateType().getCode(), request.getCertificateType().getPrefix());
                if (certificateNo == null) {
                    certificateNo = request.getCertificateType().getInitNo();
                }
                certificatePO.setCertificateImage(request.getCertificateType().getCertificateImage());
                if (request.getCertificateType().getBatchNo() != null) {
                    certificatePO.setBatchNo(request.getCertificateType().getBatchNo());
                } else {
                    certificatePO.setBatchNo(DateTimeUtils.getLongDate(new Date()));
                }
                certificatePO.setCertificateType(request.getCertificateType().getCode());
                certificatePO.setStampImage(request.getCertificateType().getStampImage());
                certificatePO.setCertificateNo(request.getCertificateType().getPrefix() + ++certificateNo);
                if (StringUtils.isNotBlank(certificatePO.getStampImage())) {
                    certificatePO.setStatus(CertificateStatusEnum.STAMPED.getCode());
                    certificatePO.setStampTime(new Date());
                }
                mongoTemplate.save(certificatePO);
            } catch (Exception e) {
                log.error("syncCertificate error request {}", request, e);
                return false;
            } finally {
                lockService.unLock(lock);
            }
        }
        return true;
    }

    public void syncCertificate() {
        log.info("syncCertificate start");
        Query query = new Query();
        query.addCriteria(Criteria.where("deleted").is(false));
        query.addCriteria(Criteria.where("sync").is(false));
        query.addCriteria(Criteria.where("received").is(true));
        List<CertificatePO> certificatePOList = mongoTemplate.find(query, CertificatePO.class);
        for (CertificatePO certificatePO : certificatePOList) {
            YLCertificateSyncRequest request = new YLCertificateSyncRequest();
            BeanUtils.copyProperties(certificatePO, request);
            request.setSyncId(certificatePO.getId());
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.add("platform", "GZ");
            HttpEntity<String> entity =
                    new HttpEntity<>(JsonUtil.toJSON(request), headers);
            QResult result = HttpClientUtils.getRestTemplate().postForObject(syncUrl, entity, QResult.class);
            if (request != null && result.data != null) {
                if (result.data.toString().equals("SUCCESS")) {
                    certificatePO.setSync(true);
                    certificatePO.setStampTime(new Date());
                }
                certificatePO.setSyncResult(result.data.toString());
                mongoTemplate.save(certificatePO);
            }
        }
    }

    public String syncCertificateFinalImage(YLCertificateFinalImageSyncRequest syncRequest) {
        try {
            log.info("syncCertificateFinalImage syncRequest {}", syncRequest);
            Query query = new Query();
            query.addCriteria(Criteria.where("id").is(syncRequest.getSyncId()));
            Update update = new Update();
            update.set("updatedTime", new Date());
            update.set("certificateFinalImage", syncRequest.getCertificateFinalImage());
            update.set("generateTime", new Date());
            mongoTemplate.updateFirst(query, update, CertificatePO.class);
            return "SUCCESS";
        } catch (Exception e) {
            log.info("syncCertificateFinalImage syncRequest error", e);
            return "FAIL";
        }
    }

    private boolean isSync(String userId, String certificateType) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.addCriteria(Criteria.where("certificateType").is(certificateType));
        return mongoTemplate.exists(query, CertificatePO.class);
    }

    private Long getMaxCertificateNo(String certificateType, String prefix) {
        Query query = new Query();
        query.addCriteria(Criteria.where("deleted").is(false));
        query.addCriteria(Criteria.where("certificateType").is(certificateType));
        Pattern pattern = Pattern.compile("^.*" + prefix + ".*$", Pattern.CASE_INSENSITIVE);
        query.addCriteria(Criteria.where("certificateNo").regex(pattern));
//        query.with(new Sort(Sort.Direction.DESC, "certificateNo"));
        Sort sort=Sort.by(Sort.Direction.DESC, "certificateNo");
        query.with(sort);
        PageRequest pageRequest = PageRequest.of(0, 1);
        List<CertificatePO> certificatePOList = mongoTemplate.find(query.with(pageRequest), CertificatePO.class);
        if (!CollectionUtils.isEmpty(certificatePOList)) {
            return Long.valueOf(certificatePOList.get(0).getCertificateNo().replace(prefix, ""));
        }
        return null;
    }
}
